/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pagerank;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
import no.uib.cipr.matrix.Vector;
import no.uib.cipr.matrix.sparse.CompColMatrix;
import no.uib.cipr.matrix.sparse.FlexCompColMatrix;
import no.uib.cipr.matrix.sparse.FlexCompRowMatrix;
import no.uib.cipr.matrix.sparse.SparseVector;

/**
 *
 * @author Sefik
 */
public class FileInput {

    public static void FileInput(String fileName) {

        File file = new File(fileName);

        try {
            BufferedReader dis = new BufferedReader(new FileReader(file));

            String integerString = dis.readLine().toString().trim();
            int hMount = Integer.parseInt(integerString);
            System.out.println("Mount of hosts is: " + integerString + ".");

            //create normal int[][] matrix
            //createMatrix(dis, hMount);

            //create row sparce matrix            
            FlexCompRowMatrix hRowMatrix = createHRowMatrix(dis, hMount);
            /*
            FlexCompRowMatrix sRowMatrix = createSRowMatrix(hRowMatrix, hMount);
            FlexCompRowMatrix gRowMatrix = createGRowMatrix(sRowMatrix, hMount);
             */
            
            //printSparceRowMatrix(hRowMatrix);
            /*
            int iteration = 3;

            for (int i = 0; i < iteration; i++) {
                SparseVector pageHRowRank = createHRowRankMatrix(hRowMatrix, i);
                //System.out.println("Vypisuju picko");
                printPageRankVectorPi(pageHRowRank);
            }
            */
            //create col sparce matrix
            dis = new BufferedReader(new FileReader(file));
            //ubrani radku
            dis.readLine();
            FlexCompColMatrix hColMatrix = createHColMatrix(dis, hMount);
            /*
            FlexCompColMatrix sRowMatrix = createSColMatrix(hColMatrix, hMount);
            FlexCompColMatrix gRowMatrix = createGColMatrix(sColMatrix, hMount);
             */
            
            //printSparceColMatrix(hColMatrix);
            SparseVector aVector = createAvector(hRowMatrix);
            int iteration = 30;

            SparseVector pageHColRank = createHColRankMatrix(hColMatrix, iteration, aVector);
                //System.out.println("Vypisuju picko");
            printPageRankVectorPi(pageHColRank);
            
            
            // dispose all the resources after using them.
            dis.close();

        } catch (FileNotFoundException e) {
            System.out.println("Error: File " + fileName + " not found!");
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void createMatrix(BufferedReader matrixDis, int hostMount) throws IOException {

        int[][] nz = new int[hostMount][hostMount];
        int[][] nz_trans = new int[hostMount][hostMount];
        int row = 0;
        int col = 0;
        String line = null;
        while ((line = matrixDis.readLine().toString()) != null) {
            int value = 0;
            String[] parseLine = processLine(line, hostMount);
            for (int i = 0; i < hostMount; i++) {
                nz[row][i] = value;
                nz_trans[i][row] = value;
            }

            for (int i = 0; i < parseLine.length; i++) {
                if (parseLine[i].contains(":")) {
                    int position = parseLine[i].indexOf(":");
                    int c = Integer.parseInt(parseLine[i].substring(0, position));
                    //avoiding links to itself
                    if (row != c) {
                        //if we want the value of links from file
                        int newValue = Integer.parseInt(parseLine[i].substring(position + 1));
                        //else use just number 1, that means, we know, that there are links, but we dont care how many
                        //newValue=1;

                        nz[row][c] = newValue;
                        nz_trans[c][row] = newValue;
                    }
                }
            }
            System.out.println("Processing " + row + "th row of the matrix.");
            row++;
        }
        System.out.println("Matrix created.");
        printMatrix(nz);
        printMatrix(nz_trans);
    }

    public static FlexCompRowMatrix createHRowMatrix(BufferedReader matrixDis, int hostMount) throws IOException {

        FlexCompRowMatrix matrix = new FlexCompRowMatrix(hostMount, hostMount);
        int row = 0;
        int col = 0;
        String line = null;
        while ((line = matrixDis.readLine().toString()) != null) {
           
            //preskocim pokud jde o prazdny radek
            //System.out.println(">"+row.trim()+"<");
            if (line.trim().equals("")) {
                //System.out.println("oriznu "+y);
                row++;
                continue;
            }
            double value = 0;
            String[] parseLine = processLine(line, hostMount);

            //counting of total links
            int totalLinks = 0;
            for (int i = 0; i < parseLine.length; i++) {
                if (parseLine[i].contains(":")) {
                    int position = parseLine[i].indexOf(":");
                    totalLinks = totalLinks + Integer.parseInt(parseLine[i].substring(position + 1));
                }
            }

            //filing of sparce matrix
            for (int i = 0; i < parseLine.length; i++) {
                if (parseLine[i].contains(":")) {
                    int position = parseLine[i].indexOf(":");
                    int c = Integer.parseInt(parseLine[i].substring(0, position));
                    //avoiding links to itself
                    if (row != c) {
                        //if we want the value of links from file
                        int links = Integer.parseInt(parseLine[i].substring(position + 1));
                        //else use just number 1, that means, we know, that there are links, but we dont care how many
                        //newValue=1;
                        value = (double) links / (double) totalLinks;
                        matrix.add(row, c, value);
                    }
                }
            }
            System.out.println("Processing " + row + "th row of the matrix.");
            row++;
             if (row > hostMount-1) {
                break;
            }
        }
        System.out.println("Matrix created.");

        //printMatrix(nz);
        //printMatrix(nz_trans);
        return matrix;
    }

    public static FlexCompRowMatrix createSRowMatrix(FlexCompRowMatrix matrix, int hostMount) throws IOException {
        int n = hostMount;
        double SEmptyValue = 1.0 / (double) n;
        SparseVector e = new SparseVector(n, 1);
        //jednotkovy vektor, proc to tam neda 1?
        for (int i = 0; i < e.size(); i++) {
            //nastavi jednicky, nejak to zlobi
            e.set(i, 1.0);
        }

        //vypoctu S matici
        //Smatrix = Hmatrix;
        for (int i = 0; i < n; i++) {
            //nastavim pro nulove radky jednotkovy radek podeleny poctem celkovych hostu
            if (matrix.getRow(i).getUsed() == 0) {
                //Smatrix.getRow(i).set(e.scale(1.0 / (double)n));
                for (int j = 0; j < n; j++) {
                    matrix.getRow(i).set(i, SEmptyValue);
                }
                //Smatrix.getRow(i).
            }
        }
        return matrix;

    }

    public static FlexCompRowMatrix createGRowMatrix(FlexCompRowMatrix matrix, int hostMount) throws IOException {
        double alpha = 0.85;
        //double accuracy = 0.001;
        int n = hostMount;
        SparseVector e = new SparseVector(n, 1);
        for (int i = 0; i < e.size(); i++) {
            e.set(i, 1.0);
        }

        for (int i = 0; i < n; i++) {
            matrix.getRow(i).scale(alpha);
            matrix.getRow(i).add(e.scale((1 - alpha) / (double) n));
        }

        return matrix;
    }

    public static FlexCompColMatrix createHColMatrix(BufferedReader matrixBR, int hostMount) throws IOException {

        FlexCompColMatrix matrix = new FlexCompColMatrix(hostMount, hostMount);
        int row = 0;
        int col = 0;
        String line = null;
        while ((line = matrixBR.readLine().toString()) != null) {

            //preskocim pokud jde o prazdny radek
            //System.out.println(">"+row.trim()+"<");
            if (line.trim().equals("")) {
                //System.out.println("oriznu "+row);
                row++;
                continue;
            }
            double value = 0;
            String[] parseLine = processLine(line, hostMount);

            //counting of total links
            int totalLinks = 0;
            for (int i = 0; i < parseLine.length; i++) {
                if (parseLine[i].contains(":")) {
                    int position = parseLine[i].indexOf(":");
                    totalLinks = totalLinks + Integer.parseInt(parseLine[i].substring(position + 1));
                }
            }

            //filing of sparce matrix
            for (int i = 0; i < parseLine.length; i++) {
                if (parseLine[i].contains(":")) {
                    int position = parseLine[i].indexOf(":");
                    int c = Integer.parseInt(parseLine[i].substring(0, position));
                    //avoiding links to itself
                    if (row != c) {
                        //if we want the value of links from file
                        int links = Integer.parseInt(parseLine[i].substring(position + 1));
                        //else use just number 1, that means, we know, that there are links, but we dont care how many
                        //newValue=1;
                        value = (double) links / (double) totalLinks;
                        //System.out.println("ukladam " + value);
                        matrix.add(c, row, value);
                    }
                }
            }
            System.out.println("Processing " + row + "th row of the matrix.");
            row++;
            if (row > (hostMount - 1)) {
                break;
            }
        }
        System.out.println("Matrix created.");

        //printMatrix(nz);
        //printMatrix(nz_trans);
        return matrix;
    }

    /*
    public static FlexCompColMatrix createSColMatrix(FlexCompColMatrix matrix, int hostMount) throws IOException {
    int n = hostMount;
    double SEmptyValue = 1.0 / (double) n;
    SparseVector e = new SparseVector(n, 1);
    //jednotkovy vektor, proc to tam neda 1?
    for (int i = 0; i < e.size(); i++) {
    //nastavi jednicky, nejak to zlobi
    e.set(i, 1.0);
    }

    //vypoctu S matici
    //Smatrix = Hmatrix;
    for (int i = 0; i < n; i++) {
    //nastavim pro nulove radky jednotkovy radek podeleny poctem celkovych hostu
    if (matrix.getRow(i).getUsed() == 0) {
    //Smatrix.getRow(i).set(e.scale(1.0 / (double)n));
    for (int j = 0; j < n; j++) {
    matrix.getRow(i).set(i, SEmptyValue);
    }
    //Smatrix.getRow(i).
    }
    }
    return matrix;

    }

    public static FlexCompColMatrix createGColMatrix(FlexCompColMatrix matrix, int hostMount) throws IOException {
    double alpha = 0.85;
    //double accuracy = 0.001;
    int n = hostMount;
    SparseVector e = new SparseVector(n, 1);
    for (int i = 0; i < e.size(); i++) {
    e.set(i, 1.0);
    }

    for (int i = 0; i < n; i++) {
    matrix.getRow(i).scale(alpha);
    matrix.getRow(i).add(e.scale((1 - alpha) / (double) n));
    }

    return matrix;
    }

     */
    public static void printMatrix(int[][] matrix) {
        System.out.println("---------------------------------------------------------");
        System.out.println("// Printing out the matrix //");
        System.out.println("---------------------------------------------------------");
        int mount = matrix.length;
        for (int i = 0; i < mount; i++) {
            for (int j = 0; j < mount; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.print("\n");
        }
        System.out.println("---------------------------------------------------------");
        System.out.println("---------------------------------------------------------");
        System.out.print("\n");
    }

    private static void printSparceRowMatrix(FlexCompRowMatrix matrix) {
        System.out.println("---------------------------------------------------------");
        System.out.println("// Printing out the matrix //");
        System.out.println("---------------------------------------------------------");
        for (int i = 0; i < matrix.numRows(); i++) {
            for (int j = 0; j < matrix.numColumns(); j++) {
                System.out.print(matrix.get(i, j) + " ");
            }
            //System.out.print("used "+matrix.getRow(i).getUsed());
            System.out.print("\n");
        }
        System.out.println("---------------------------------------------------------");
        System.out.println("---------------------------------------------------------");
        System.out.print("\n");
    }

    private static void printSparceColMatrix(FlexCompColMatrix matrix) {
        System.out.println("---------------------------------------------------------");
        System.out.println("// Printing out the matrix //");
        System.out.println("---------------------------------------------------------");
        for (int i = 0; i < matrix.numRows(); i++) {
            for (int j = 0; j < matrix.numColumns(); j++) {
                System.out.print(matrix.get(i, j) + " ");
            }
            System.out.print("\n");
        }
        System.out.println("---------------------------------------------------------");
        System.out.println("---------------------------------------------------------");
        System.out.print("\n");
    }

    private static void printPageRankVectorPi(SparseVector pi) {
        System.out.println("---------------------------------------------------------");
        System.out.println("// Printing out pagerank vector pi //");
        System.out.println("---------------------------------------------------------");
        for (int i = 0; i < pi.size(); i++) { //nastavi jednickz, nejak to ylobi
            System.out.print(pi.get(i) + " ");
        }
        System.out.print("\n");
        System.out.println("---------------------------------------------------------");
        System.out.println("---------------------------------------------------------");
        System.out.print("\n");
    }

    public static String[] processLine(String aLine, int mount) {
        //System.out.println("Process line");
        Scanner scanner = new Scanner(aLine);
        scanner.useDelimiter(" ");
        String trimALine = aLine.trim();
        int minMount = trimALine.length();
        minMount = (int) (minMount - minMount / (Integer.toString(mount).length() * 2 + 1));

        String[] clearRow = createClearRow(minMount);
        int position = 0;
        while (scanner.hasNext()) {
            String part = scanner.next();
            clearRow[position] = part.trim();
            position++;
            //log("Name is : " + quote(name.trim()) + ", and Value is : " + quote(value.trim()) );
        }
        scanner.close();
        //no need to call scanner.close(), since the source is a String
        return clearRow;
    }

    public static String[] createClearRow(int hostMount) {
        String[] cRow = new String[hostMount];
        for (int i = 0; i < hostMount; i++) {
            cRow[i] = "";
        }
        return cRow;
    }

    public static SparseVector createHColRankMatrix(FlexCompColMatrix matrix, int iteration, SparseVector a) {
        double alpha = 0.85;
        int n = matrix.numColumns();
        SparseVector pi = new SparseVector(n, 1);
        SparseVector resultpi = new SparseVector(n, 1);
        SparseVector zeroVector = new SparseVector(n, 0);

        //jednotkovy vektor, proc to tam neda 1?
        for (int i = 0; i < pi.size(); i++) { //nastavi jednickz, nejak to ylobi
            pi.set(i, 1.0 / (double) n);
            zeroVector.set(i, (double) 0);
        }

        //e vector creating
        SparseVector eVector = new SparseVector(n, 1);
        for (int i = 0; i < eVector.size(); i++) {
            eVector.set(i, 1.0);
        }

        //a vector creating
        //zazavorkovano, protoze se a vector tvori
        /*
        SparseVector a = zeroVector;
        for (int i = 0; i < matrix.numColumns(); i++) {
            if (matrix.getColumn(i).equals(zeroVector)) {
                a.set(i, (double) 1);
            }
        }
        */

        SparseVector x = new SparseVector(n, 1);
        x.set(eVector);
        //iteration of counting pi vector
        for (int j = 0; j < iteration; j++) {
            //nesmime zapomenout, ze ze zadani pocitame piT!!!
            //je treba zpetne transponovat a predavat jako netransponovany vektor pi!!

            
            //vyuzivame toho, ze AT * B = A * BT
            //piT* a = pi * aT = alphaPiA
            double alphaPiA = pi.dot(a);
            //alpha* (pi * aT) = alphaPiA
            alphaPiA = alpha * alphaPiA;
            //System.out.println("prvni vysledek " + alphaPiA);
            //(alpha* (pi * aT)  + 1 - alpha)/n = alphaPiA
            alphaPiA = (alphaPiA + (1 - alpha))/n;
            //System.out.println("pocet radku " + n);
            //System.out.println("druhy vysledek " + alphaPiA);
            //((alpha* (pi * aT)  + 1 - alpha)/n)*eT = resultpi;
            x.scale(alphaPiA);
            resultpi.set(x);
            //az k tomuto mistu pocita dobre

            /*
             * transMultAdd(double alpha, Vector x, Vector y)
             *  y = alpha*AT*x + y
             * resultpi = alpha*MT*pi + resultpi
             */
            
            //matrix.transMultAdd(alpha, pi, resultpi);
            matrix.multAdd(alpha, pi, resultpi);
            
            pi.set(resultpi);
            //zeroing help vectors
            resultpi.set(zeroVector);
            x.set(eVector);
            //printPageRankVectorPi(pi);
        }

        return pi;

    }

    public static SparseVector createHRowRankMatrix(FlexCompRowMatrix matrix, int iteration) {
        double alpha = 0.85;
        int n = matrix.numRows();
        SparseVector pi = new SparseVector(n, 1);
        SparseVector resultpi = new SparseVector(n, 1);
        SparseVector zeroVector = new SparseVector(n, 0);
        //e vector creating
        SparseVector e = new SparseVector(n, 1);

        //jednotkovy vektor, proc to tam neda 1?
        for (int i = 0; i < pi.size(); i++) { //nastavi jednickz, nejak to ylobi
            pi.set(i, 1.0 / (double) n);
            zeroVector.set(i, (double) 0);
            e.set(i, 1.0);
        }
    

        //a vector creating
        SparseVector a = zeroVector;
        SparseVector help = zeroVector;
        //System.out.println("vypisuju zero vektor");
        //printPageRankVectorPi(zeroVector);

        for (int i = 0; i < matrix.numRows(); i++) {
            //System.out.println("vypisuju matrix get row");
            //printPageRankVectorPi(matrix.getRow(i));
            help = matrix.getRow(i);
            if (help.toString().equals(zeroVector.toString())) {
                System.out.println("jsem v equal");
                a.set(i, (double) 1);
            }
        }

        /*
        System.out.println("vypisuju acko");
        printPageRankVectorPi(a);
        */

        SparseVector resultL = zeroVector;
        //iteration of counting pi vector
        for (int j = 0; j < iteration; j++) {
            //nesmime zapomenout, ze ze zadani pocitame piT!!!
            //je treba zpetne transponovat a predavat jako netransponovany vektor pi!!

            //vyuzivame toho, ze AT * B = A * BT
            //piT* a = pi * aT = alphaPiA
            double alphaPiA = pi.dot(a);
            //alpha* (pi * aT) = alphaPiA
            alphaPiA = alpha * alphaPiA;
            //(alpha* (pi * aT)  + 1 - alpha)/n = alphaPiA
            alphaPiA = (alphaPiA + (1 - alpha)) / n;
            //((alpha* (pi * aT)  + 1 - alpha)/n)*eT = resultpi;
            resultpi = e.scale(alphaPiA);

            /*
            for (int i = 0; i < matrix.numColumns(); i++) {
                    alphaPiAVector.add(i, alphaPiA);
            }
            */

            matrix.mult(alpha, pi, resultL);

            resultpi.add(resultL);
            pi = resultpi;
        }

        return pi;

    }

    public static SparseVector createAvector(FlexCompRowMatrix matrix) {
        int n = matrix.numRows();
        SparseVector zeroVector = new SparseVector(n, 0);

        //jednotkovy vektor, proc to tam neda 1?
        for (int i = 0; i < zeroVector.size(); i++) { //nastavi jednickz, nejak to ylobi
            zeroVector.set(i, (double) 0);
        }


        //a vector creating
        SparseVector a = zeroVector;
        SparseVector help = zeroVector;

        for (int i = 0; i < matrix.numRows(); i++) {
            //System.out.println("vypisuju matrix get row");
            //printPageRankVectorPi(matrix.getRow(i));
            help = matrix.getRow(i);
            if (help.toString().equals(zeroVector.toString())) {
                a.set(i, (double) 1);
            }
        }

        /*
        System.out.println("vypisuju acko");
        printPageRankVectorPi(a);        
        */
        
        return a;

    }
}
